package com.huishu.commons.utlis;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.common.utils.UuidUtils;
import com.huishu.commons.constant.WxConstact;
import com.huishu.commons.exception.BaseException;
import com.huishu.commons.pojo.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.*;
import java.security.spec.InvalidParameterSpecException;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信工具类
 */
@Slf4j
public class WechatUtil {

    //获取AccessToken路径
    private static final String AccessToken_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET";

    //获取二维码路径
    private static final String WxCode_URL = "https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=ACCESS_TOKEN";

    public static Map<String, WeChatParam> weChatParams = new HashMap<>();


    static {
        weChatParams.put("huishu", new WeChatParam("wx0ad20c1f6e67d2d2", "46c8931808a850141b32ab798135fa69"));
    }


    public static class WeChatParam {

        private String appid;

        private String secret;

        public WeChatParam(String appid, String secret) {
            this.appid = appid;
            this.secret = secret;
        }

        public String getAppid() {
            return appid;
        }

        public void setAppid(String appid) {
            this.appid = appid;
        }

        public String getSecret() {
            return secret;
        }

        public void setSecret(String secret) {
            this.secret = secret;
        }
    }

    /**
     * 根据微信code  获取sessionkey 和openid
     *
     * @param code
     * @return
     */
    public static JSONObject getSessionKeyOrOpenId(String code, WeChatParam weChatParam) throws IOException {
        //微信端登录code
        String url = "https://api.weixin.qq.com/sns/jscode2session";
        Map<String, Object> maps = new HashMap<>();
        maps.put("appid", weChatParam.getAppid());
        maps.put("secret", weChatParam.getSecret());
        maps.put("js_code", code);
        maps.put("grant_type", "authorization_code");
        JSONObject jsonObject = HttpUtils.doGet(url, maps);
        log.info("微信code请求返回JSONObject:{}", jsonObject.toJSONString());
        return jsonObject;
    }


    /**
     * 解析微信小程序用户基本信息
     *
     * @param encryptedData
     * @param sessionKey
     * @param iv
     * @return
     */
    public static JSONObject getUserInfo(String encryptedData, String sessionKey, String iv) {
        // 被加密的数据
        byte[] dataByte = Base64.getDecoder().decode(encryptedData);
        // 加密秘钥
        byte[] keyByte = Base64.getDecoder().decode(sessionKey);
        // 偏移量
        byte[] ivByte = Base64.getDecoder().decode(iv);
        try {
            // 如果密钥不足16位，那么就补足.  这个if 中的内容很重要
            int base = 16;
            if (keyByte.length % base != 0) {
                int groups = keyByte.length / base + (keyByte.length % base != 0 ? 1 : 0);
                byte[] temp = new byte[groups * base];
                Arrays.fill(temp, (byte) 0);
                System.arraycopy(keyByte, 0, temp, 0, keyByte.length);
                keyByte = temp;
            }
            // 初始化
            Security.addProvider(new BouncyCastleProvider());
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
            //Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
            SecretKeySpec spec = new SecretKeySpec(keyByte, "AES");
            AlgorithmParameters parameters = AlgorithmParameters.getInstance("AES");
            parameters.init(new IvParameterSpec(ivByte));
            cipher.init(Cipher.DECRYPT_MODE, spec, parameters);// 初始化
            byte[] resultByte = cipher.doFinal(dataByte);
            if (null != resultByte && resultByte.length > 0) {
                String result = new String(resultByte, "UTF-8");
                return JSON.parseObject(result);
            }
        } catch (NoSuchAlgorithmException e) {
            log.error(e.getMessage(), e);
        } catch (NoSuchPaddingException e) {
            log.error(e.getMessage(), e);
        } catch (InvalidParameterSpecException e) {
            log.error(e.getMessage(), e);
        } catch (IllegalBlockSizeException e) {
            log.error(e.getMessage(), e);
        } catch (BadPaddingException e) {
            log.error(e.getMessage(), e);
        } catch (UnsupportedEncodingException e) {
            log.error(e.getMessage(), e);
        } catch (InvalidKeyException e) {
            log.error(e.getMessage(), e);
        } catch (InvalidAlgorithmParameterException e) {
            log.error(e.getMessage(), e);
        } catch (NoSuchProviderException e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }


    /**
     * 用于获取access_token
     *
     * @return access_token
     * @throws Exception
     */
    public static String getAccessToken(String appId, String secret) throws Exception {
        String requestUrl = AccessToken_URL.replace("APPID", appId).replace("APPSECRET", secret);
        URL url = new URL(requestUrl);
        // 打开和URL之间的连接
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("POST");
        // 设置通用的请求属性
        connection.setRequestProperty("Content-Type", "application/json");
        connection.setRequestProperty("Connection", "Keep-Alive");
        connection.setUseCaches(false);
        connection.setDoOutput(true);
        connection.setDoInput(true);

        // 得到请求的输出流对象
        DataOutputStream out = new DataOutputStream(connection.getOutputStream());
        out.writeBytes("");
        out.flush();
        out.close();

        // 建立实际的连接
        connection.connect();
        // 定义 BufferedReader输入流来读取URL的响应
        BufferedReader in = null;
        if (requestUrl.contains("nlp"))
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "GBK"));
        else
            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"));
        String result = "";
        String getLine;
        while ((getLine = in.readLine()) != null) {
            result += getLine;
        }
        in.close();
        JSONObject jsonObject = JSON.parseObject(result);
        log.info("获取access_token:{}", jsonObject.toJSONString());
        String accesstoken = jsonObject.getString("access_token");
        return accesstoken;
    }


    public static String generateQrCode(String scene, String page) {
        try {
            String path = System.getProperty("user.dir") + File.separator + "xxx" + ".png";
            log.info(path);
            String accessToken = WechatUtil.getAccessToken(WxConstact.APPID, WxConstact.SECRET);
            log.info("获取小程序二维码:参数:scene:{},page:{}", scene, page);
            String wxCodeURL = WxCode_URL.replace("ACCESS_TOKEN", accessToken);
            //调用微信接口生成二维码
            URL url = new URL(wxCodeURL);
            HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
            // POST
            urlConnection.setRequestMethod("POST");
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            PrintWriter printWriter = new PrintWriter(urlConnection.getOutputStream());
            // 发送请求参数
            JSONObject paramJson = new JSONObject();
            paramJson.put("scene", scene);
            paramJson.put("page", page);
            paramJson.put("width", 430);
            paramJson.put("is_hyaline", true);
            paramJson.put("auto_color", true);
            printWriter.write(paramJson.toString());
            // flush输出流的缓冲
            printWriter.flush();
            //开始获取数据
            byte[] bytes = inputStreamToByte(urlConnection.getInputStream());
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
            log.error("获取小程序码失败", e);
        }
        return null;
    }

    private static byte[] inputStreamToByte(InputStream inputStream) throws IOException {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        int ch;
        while ((ch = inputStream.read()) != -1) {
            outputStream.write(ch);
        }
        byte[] imgData = outputStream.toByteArray();
        outputStream.close();
        return imgData;
    }


    /*
     * 获取 二维码图片
     *
     */
    public static String getAppletQrCode(String accessToken, String shareCode, String page, String filename) {
        if (StringUtils.isBlank(filename)) {
            filename = UuidUtils.generateUuid();
        }
        String path = System.getProperty("user.dir") + File.separator + filename + ".png";
        try {
            String wxCodeURL = WxCode_URL.replace("ACCESS_TOKEN", accessToken);
            URL url = new URL(wxCodeURL);
            HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
            httpURLConnection.setRequestMethod("POST");// 提交模式
            // 发送POST请求必须设置如下两行
            httpURLConnection.setDoOutput(true);
            httpURLConnection.setDoInput(true);
            // 获取URLConnection对象对应的输出流
            PrintWriter printWriter = new PrintWriter(httpURLConnection.getOutputStream());
            // 发送请求参数
            JSONObject paramJson = new JSONObject();
            paramJson.put("scene", shareCode);
//            "pages/factorydetail/factorydetail"
            paramJson.put("page", page);
            paramJson.put("width", 430);
            paramJson.put("is_hyaline", true);
            paramJson.put("auto_color", true);
            log.info("请求参数:{}", paramJson.toJSONString());
            printWriter.write(paramJson.toJSONString());
            // flush输出流的缓冲
            printWriter.flush();
            // 开始获取数据
            InputStream inputStream = httpURLConnection.getInputStream();
            BufferedInputStream bis = new BufferedInputStream(inputStream);
            OutputStream os = new FileOutputStream(new File(path));
            int len;
            byte[] arr = new byte[inputStream.available()];
            while ((len = bis.read(arr)) != -1) {
                os.write(arr, 0, len);
                os.flush();
            }
//            System.out.println(new String(arr));
            os.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return path;
    }

    /**
     * 根据code获取openId
     *
     * @param code
     * @return
     */
    public static String getOpenId(String code) {
        try {
            WeChatParam weChatParam = new WeChatParam(WxConstact.APPID, WxConstact.SECRET);
            JSONObject sessionKeyOpenId = getSessionKeyOrOpenId(code, weChatParam);
            String openid = sessionKeyOpenId.getString("openid");
            log.info("sessionKeyOpenId :{}", sessionKeyOpenId.toJSONString());
            if (StringUtils.isBlank(openid)) {
                throw new BaseException("无效的code");
            }
            return openid;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    public static void main(String[] args) throws Exception {
        //String accessToken = getAccessToken("wx2c63b351d8b11185", "73e6abe9ac8c086f01336efdfb0d41c4");
        //String qrCodeUrl = getAppletQrCode(accessToken, "gssc", "pages/index/index", "公司手册");
        //System.out.println(qrCodeUrl);
        System.out.println(System.currentTimeMillis());
//        System.out.println(getSessionKeyOrOpenId("05319pGa19ztJA0MY2Ha15kf5t419pGd", weChatParams.get("trader")));
    }

}
